package com.googlecode.curvedmetromaps.core.logic.costfunction;

import java.util.ArrayList;

import org.jbox2d.common.Vec2;

import com.googlecode.curvedmetromaps.core.model.MetroEdge;
import com.googlecode.curvedmetromaps.core.model.MetroLine;
import com.googlecode.curvedmetromaps.core.model.MetroMap;
import com.googlecode.curvedmetromaps.core.model.MetroStation;

public class InflectionCost extends BaseCost {

	public ArrayList<Integer>	inflectionPoints	= new ArrayList<Integer>();

	public InflectionCost(MetroMap map) {
		super(map);
		createWeight("base", "Base weight", 20);
	}

	@Override
	public String getName() {
		return "Inflection count";
	}

	@Override
	public double calculateCost() {
		double result = 0;
		inflectionPoints.clear();

		for (MetroLine line : map.lines) {
			float lastSign = 0;
			for (int i = 1; i < line.stations.length; i++) {
				MetroStation m1 = line.stations[i - 1];
				MetroStation m2 = line.stations[i];
				MetroEdge edge = map.getEdge(m1, m2);

				Vec2 p0 = edge.getCP();
				Vec2 p1 = new Vec2(m1.x, m1.y);
				Vec2 p2 = new Vec2(m2.x, m2.y);
				float sign = sideOfLine(p0, p1, p2);

				if (i >= 2) {
					if ((sign != 0) && (lastSign != 0) && (sign != lastSign)) {
						// Sign has changed from left to right or from right to
						// left.
						result++;
						inflectionPoints.add(m1.id);
					}
				}

				if (sign != 0) {
					lastSign = sign;
				}
			}
		}

		// Calculate inflection ratio by dividing by maximum number of
		// inflection points.
		result /= map.edgeArray.length;
		return getWeight("base") * result;
	}

	/**
	 * If you stand at p1 looking towards p2, this function determines whether
	 * p0 is to the left, colinear, or to the right.
	 * @return -1 if p0 is left of the line from p1 to p2, 0 if p0 lies on the
	 *         line, 1 if p0 lies to the right of the line.
	 */
	private float sideOfLine(Vec2 p0, Vec2 p1, Vec2 p2) {
		return Math.signum((p2.x - p1.x) * (p0.y - p1.y) - (p2.y - p1.y) * (p0.x - p1.x));
	}
}
